/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Eclipse Public License (EPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/eclipse-1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.mmtk.plan.scale.colors;

import org.mmtk.plan.CollectorContext;
import org.mmtk.plan.StopTheWorldCollector;
import org.mmtk.plan.scale.Scale;
import org.mmtk.plan.scale.ScaleCollector;
import org.mmtk.plan.scale.ScaleTrace;
import org.mmtk.plan.scale.utils.ScaleLogger;
import org.mmtk.utility.Log;
import org.mmtk.utility.options.Options;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Uninterruptible;

/**
 * This class implements <i>per-collector thread</i> behavior and state for the
 * <i>MS</i> plan, which implements a full-heap mark-sweep collector.
 * <p>
 * 
 * Specifically, this class defines <i>MS</i> collection behavior (through
 * <code>trace</code> and the <code>collectionPhase</code> method).
 * <p>
 * 
 * @see SColors for an overview of the mark-sweep algorithm.
 *      <p>
 * 
 * @see SColors
 * @see SColorsMutator
 * @see StopTheWorldCollector
 * @see CollectorContext
 */
@Uninterruptible
public class SColorsCollector extends ScaleCollector {

	/****************************************************************************
	 * Instance fields
	 */
	private Helper helper;	
	private SColorsTraceLocal sColorsTraceLocal;
	private SColorsTraceLocal sColorsPrivateTraceLocal;
	
	public SColorsCollector() {
		sColorsTraceLocal= new SColorsTraceLocal("sColorsTraceLocal", global().scaleTrace);
		traceLocal = sColorsTraceLocal;
		if(VM.activePlan.collectorCount() > 1) {
			multiThreaded = true;
			privateScaleTrace = new ScaleTrace(Scale.metaDataSpace);
			sColorsPrivateTraceLocal = new SColorsTraceLocal("sColorsPrivateTraceLocal", SColors.PRIVATE_SCAN_COLOR, privateScaleTrace);
			privateTraceLocal = sColorsPrivateTraceLocal;		
		}
		else {
			multiThreaded = false;
			privateScaleTrace = null;
			privateTraceLocal = null;
		}		
	}
	/****************************************************************************
	 * Collection
	 */

	/**
	 * Perform a per-collector collection phase.
	 * 
	 * @param phaseId
	 *            The collection phase to perform
	 * @param primary
	 *            Perform any single-threaded activities using this thread.
	 */
	@Inline
	@Override
	public void collectionPhase(short phaseId, boolean primary) {
		
		if (phaseId == SColors.PREPARE) {
			//nothing is done by the parent
			super.collectionPhase(phaseId, primary);
			
			//try to grab color table index - attempt to become helper
			helper = Helper.getHelper(primary);
			if(helper != null) {
				if(Options.scaleDebug.getValue() > 5) {
					ScaleLogger.logConcMessage("Will be helper");
				}
			} else {
				if(Options.scaleDebug.getValue() > 5) {
					ScaleLogger.logConcMessage("Will not be helper");
				}
			}
			return;
		}
		
		if (phaseId == Scale.prepareClosure) {
			if(Options.scaleDebug.getValue() > 5) {
				ScaleLogger.logConcMessage("SColorsCollector.collectionPhase, phase=prepareClosure, calling super");
			}
			super.collectionPhase(phaseId, primary);
			if(Options.scaleDebug.getValue() > 5) {
				ScaleLogger.logConcMessage("SClolorsCollector.collectionPhase, phase=prepareClosure, after super");
			}
			if(helper != null) {
				//make roots available to others
				if(Options.scaleDebug.getValue() > 5) {
					ScaleLogger.logConcMessage("SClolorsCollector.collectionPhase, phase=prepareClosure, calling flushHelpers");
				}
				sColorsTraceLocal.flushHelpers();
			}
			return;
		}
		
		super.collectionPhase(phaseId, primary);
	}
	
	protected void doFixClosure(boolean primary) {
		if (helper == null) {
			// regular threads trace from collected roots
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - tracer starts");
			}
			sColorsTraceLocal.completeTrace();
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - tracer is done");
			}
			SColors.reportTraceDone(false);
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - tracer reported");
			}
		} else {
			// helper threads trace from random live objects
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - helper starts");
			}
			while (!SColors.tracersDone() && !Helper.isDone()) {
				if(Options.scaleDebug.getValue() > 1) {
					ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - helper will help");
				}
				helper.help();
			}
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - helper is done");
			}
			SColors.reportTraceDone(true);
			if(Options.scaleDebug.getValue() > 1) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - helper reported");
			}
		}
		while(!SColors.isTraceDone()) {
			//ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - waiting till all the tracers and helpers will exit");
		}
		ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - waited for all the tracers and helpers");
		//complete color trace
		while(true) {		
			if(Options.scaleDebug.getValue() > 3) {
				ScaleLogger.acquireLogLock();		
				Log.prependThreadId();
				Log.write("Before completeColorsTrace, tracedDeadObjects=");
				Log.writeln(sColorsTraceLocal.getTracedDeadObjects());
				Log.flush();
				ScaleLogger.releaseLogLock();
			}
			sColorsTraceLocal.completeColorsTrace();
			if(Options.scaleDebug.getValue() > 3) {
				ScaleLogger.acquireLogLock();		
				Log.prependThreadId();
				Log.write("After completeColorsTrace, tracedDeadObjects=");
				Log.writeln(sColorsTraceLocal.getTracedDeadObjects());
				Log.flush();
				ScaleLogger.releaseLogLock();
			}
			SColors.reportCompleteTraceDone(sColorsTraceLocal.getTracedDeadObjects());
			if(Options.scaleDebug.getValue() > 3) {
				ScaleLogger.logConcMessage("SClolorsCollector.doFixClosure - complete tracer reported");
			}
			while(!global().isCompleteTraceDone()) {
				//wait for all to complete
			}
			if(!SColors.isMadeColorsLive()) {
				break;
			}
		}
	}
	
	
	//single threaded
	protected void doCheckClosure() {
		//todo - collect additional roots from live colors
		//long newRoots = Color.getAllSavedValues(traceLocal);
		//Log.prependThreadId();
		//Log.write("SColorsCollector.doCheckClosure - newRoots=");
		//Log.writeln(newRoots);
		sColorsTraceLocal.completeMetrixTrace(false, false, false);
		//traceLocal.completeMetrixTrace(false, false);
	}

	/****************************************************************************
	 * Miscellaneous
	 */

	/** @return The active global plan as an <code>MS</code> instance. */
	@Inline
	private static SColors global() {
		return (SColors) VM.activePlan.global();
	}
}
